/*
 * 
 * @Description: This repository is used to draw some simple geometric shapes on the screen, 
 *				 including circles, filled circles, straight lines, anti-aliased straight lines, 
 *				 arcs, rounded rectangles and so on. Can let us visualize a variety of complex 
 *				 shapes on the screen is how to draw!
 *
 * @Version: v1.0.0
 * @Author: Hao(bds)
 * @Date: 2023/11/03
 * @Repository: https://gitee.com/bds123/draw_graphs
 */

#include <stdlib.h>
#include <math.h>
#include "draw.h"

static color_t blend_with_black(color_t color, float alpha) 
{
    uint16_t r = (color & 0xF800) >> 8;
    uint16_t g = (color & 0x07E0) >> 3;
    uint16_t b = (color & 0x001F) << 3;

    r = (uint16_t)(r * alpha) & 0xF8;
    g = (uint16_t)(g * alpha) & 0xFC;
    b = (uint16_t)(b * alpha) & 0xF8;

    return (r << 8) | (g << 3) | (b >> 3);
}	

void draw_line_ex(int16_t x1, int16_t y1, int16_t x2, int16_t y2, color_t c, bool anti_aliasing) 
{
    int16_t n, dx, dy, sgndx, sgndy, dxabs, dyabs, x, y, drawx, drawy;

    dx = x2 - x1;
    dy = y2 - y1;
    dxabs = (dx > 0) ? dx : -dx;
    dyabs = (dy > 0) ? dy : -dy;
    sgndx = (dx > 0) ? 1 : -1;
    sgndy = (dy > 0) ? 1 : -1;
    x = dyabs >> 1;
    y = dxabs >> 1;
    drawx = x1;
    drawy = y1;

    __draw_pixel(drawx, drawy, c);

    if (dxabs >= dyabs) {
        int aa_direction = (sgndy > 0) ? 1 : -1;  // Dynamically choose anti-aliasing direction
        for (n = 0; n < dxabs; n++) {
            y += dyabs;
            if (y >= dxabs) {
                y -= dxabs;
                drawy += sgndy;
            }
            drawx += sgndx;
            __draw_pixel(drawx, drawy, c);
            
			if (anti_aliasing) {
				// Apply anti-aliasing for neighboring pixels
				float alpha = (float)y / (float)dxabs;
				__draw_pixel(drawx, drawy + aa_direction, blend_with_black(c, alpha));
				__draw_pixel(drawx, drawy - aa_direction, blend_with_black(c, 1.0 - alpha));
			}
        }
    } else {
        int aa_direction = (sgndx > 0) ? 1 : -1;  // Dynamically choose anti-aliasing direction
        for (n = 0; n < dyabs; n++) {
            x += dxabs;
            if (x >= dyabs) {
                x -= dyabs;
                drawx += sgndx;
            }
            drawy += sgndy;
            __draw_pixel(drawx, drawy, c);
			
            if (anti_aliasing) {
				// Apply anti-aliasing for neighboring pixels
				float alpha = (float)x / (float)dyabs;
				__draw_pixel(drawx + aa_direction, drawy, blend_with_black(c, alpha));
				__draw_pixel(drawx - aa_direction, drawy, blend_with_black(c, 1.0 - alpha));
			}
        }
    }
}

void draw_circle( int16_t x0, int16_t y0, int16_t r, int16_t c )
{
   int16_t x,y,xd,yd,e;

   if ( x0<0 ) return;
   if ( y0<0 ) return;
   if ( r<=0 ) return;

   xd = 1 - (r << 1);
   yd = 0;
   e = 0;
   x = r;
   y = 0;

   while ( x >= y ) {
		__draw_pixel(x0 - x, y0 + y, c);
		__draw_pixel(x0 - x, y0 - y, c);
		__draw_pixel(x0 + x, y0 + y, c);
		__draw_pixel(x0 + x, y0 - y, c);
		__draw_pixel(x0 - y, y0 + x, c);
		__draw_pixel(x0 - y, y0 - x, c);
		__draw_pixel(x0 + y, y0 + x, c);
		__draw_pixel(x0 + y, y0 - x, c);

		y++;
		e += yd;
		yd += 2;
		if ( ((e << 1) + xd) > 0 ) {
		 x--;
		 e += xd;
		 xd += 2;
		}
   }
}

void draw_fill_circle( int16_t x0, int16_t y0, int16_t r, int16_t c )
{
	int16_t  x,y,xd;

	if ( x0<0 ) return;
	if ( y0<0 ) return;
	if ( r<=0 ) return;

	xd = 3 - (r << 1);
	x = 0;
	y = r;

	while ( x <= y ) {
		if( y > 0 ) {
			draw_line(x0 - x, y0 - y,x0 - x, y0 + y, c);
			draw_line(x0 + x, y0 - y,x0 + x, y0 + y, c);
		}
		if( x > 0 ) {
			draw_line(x0 - y, y0 - x,x0 - y, y0 + x, c);
			draw_line(x0 + y, y0 - x,x0 + y, y0 + x, c);
		}
		if ( xd < 0 ) {
			xd += (x << 2) + 6;
		} else {
			xd += ((x - y) << 2) + 10;
			y--;
		}
		x++;
	}
	draw_circle(x0, y0, r,c);
}

void draw_arc( int16_t x0, int16_t y0, int16_t r, int16_t s, int16_t c )
{
	int16_t x,y,xd,yd,e;

	if ( x0<0 ) return;
	if ( y0<0 ) return;
	if ( r<=0 ) return;

	xd = 1 - (r << 1);
	yd = 0;
	e = 0;
	x = r;
	y = 0;

	while ( x >= y ) {
		// Q1
		if ( s & 0x01 ) __draw_pixel(x0 + x, y0 - y, c);
		if ( s & 0x02 ) __draw_pixel(x0 + y, y0 - x, c);

		// Q2
		if ( s & 0x04 ) __draw_pixel(x0 - y, y0 - x, c);
		if ( s & 0x08 ) __draw_pixel(x0 - x, y0 - y, c);

		// Q3
		if ( s & 0x10 ) __draw_pixel(x0 - x, y0 + y, c);
		if ( s & 0x20 ) __draw_pixel(x0 - y, y0 + x, c);

		// Q4
		if ( s & 0x40 ) __draw_pixel(x0 + y, y0 + x, c);
		if ( s & 0x80 ) __draw_pixel(x0 + x, y0 + y, c);

		y++;
		e += yd;
		yd += 2;
		if ( ((e << 1) + xd) > 0 ) {
		 x--;
		 e += xd;
		 xd += 2;
		}
	}
}

void draw_round_rec( int16_t x1, int16_t y1, int16_t x2, int16_t y2, int16_t r, int16_t c )
{
	int16_t n;
	if ( x2 < x1 ) {
	  n = x2;
	  x2 = x1;
	  x1 = n;
	}
	if ( y2 < y1 ) {
	  n = y2;
	  y2 = y1;
	  y1 = n;
	}

	if ( r > x2 ) return;
	if ( r > y2 ) return;

	draw_line(x1+r, y1, x2-r, y1, c);
	draw_line(x1+r, y2, x2-r, y2, c);
	draw_line(x1, y1+r, x1, y2-r, c);
	draw_line(x2, y1+r, x2, y2-r, c);
	draw_arc(x1+r, y1+r, r, 0x0C, c);
	draw_arc(x2-r, y1+r, r, 0x03, c);
	draw_arc(x1+r, y2-r, r, 0x30, c);
	draw_arc(x2-r, y2-r, r, 0xC0, c);
}

void draw_fill_rec( int16_t x1, int16_t y1, int16_t x2, int16_t y2, int16_t c )
{
	int16_t n,m;

	if ( x2 < x1 ) {
	  n = x2;
	  x2 = x1;
	  x1 = n;
	}
	if ( y2 < y1 ) {
	  n = y2;
	  y2 = y1;
	  y1 = n;
	}

	for( m=y1; m<=y2; m++ ) {
	  for( n=x1; n<=x2; n++ ) {
		 __draw_pixel(n,m,c);
	  }
	}
}

void draw_fill_round_rec( int16_t x1, int16_t y1, int16_t x2, int16_t y2, int16_t r, int16_t c )
{
	int16_t  x,y,xd;

	if ( x2 < x1 ) {
		x = x2;
		x2 = x1;
		x1 = x;
	}
	if ( y2 < y1 ) {
		y = y2;
		y2 = y1;
		y1 = y;
	}

	if ( r<=0 ) return;

	xd = 3 - (r << 1);
	x = 0;
	y = r;

	draw_fill_rec(x1 + r, y1, x2 - r, y2, c);

	while ( x <= y ) {
		if( y > 0 ) {
			draw_line(x2 + x - r, y1 - y + r, x2+ x - r, y + y2 - r, c);
			draw_line(x1 - x + r, y1 - y + r, x1- x + r, y + y2 - r, c);
		}
		if( x > 0 ) {
			draw_line(x1 - y + r, y1 - x + r, x1 - y + r, x + y2 - r, c);
			draw_line(x2 + y - r, y1 - x + r, x2 + y - r, x + y2 - r, c);
		}
		if ( xd < 0 ) {
			xd += (x << 2) + 6;
		} else {
			xd += ((x - y) << 2) + 10;
			y--;
		}
		x++;
	}
}

void gui_draw_wide_line(int16_t x1, int16_t y1, int16_t x2, int16_t y2, color_t c, int16_t width) 
{
    int16_t n, dx, dy, sgndx, sgndy, dxabs, dyabs, x, y, drawx, drawy;
    int16_t offset;

    dx = x2 - x1;
    dy = y2 - y1;
    dxabs = (dx > 0) ? dx : -dx;
    dyabs = (dy > 0) ? dy : -dy;
    sgndx = (dx > 0) ? 1 : -1;
    sgndy = (dy > 0) ? 1 : -1;
    x = dyabs >> 1;
    y = dxabs >> 1;
    drawx = x1;
    drawy = y1;

    if (dxabs >= dyabs) {  // Use horizontal offset if |slope| < 1
        for (offset = -width/2; offset < width/2; ++offset) {
            __draw_pixel(drawx, drawy + offset, c);
        }

        for (n = 0; n < dxabs; ++n) {
            y += dyabs;
            if (y >= dxabs) {
                y -= dxabs;
                drawy += sgndy;
            }
            drawx += sgndx;

            for (offset = -width/2; offset < width/2; ++offset) {
                __draw_pixel(drawx, drawy + offset, c);
            }
        }
    } else {  // Use vertical offset if |slope| >= 1
        for (offset = -width/2; offset < width/2; ++offset) {
            __draw_pixel(drawx + offset, drawy, c);
        }

        for (n = 0; n < dyabs; ++n) {
            x += dxabs;
            if (x >= dyabs) {
                x -= dyabs;
                drawx += sgndx;
            }
            drawy += sgndy;

            for (offset = -width/2; offset < width/2; ++offset) {
                __draw_pixel(drawx + offset, drawy, c);
            }
        }
    }
}






